package logicaDePredicados;

import java.util.ArrayList;
import java.util.Iterator;

import exceptions.UnBalancedExpressionException;
import exceptions.UnDecidibleValueException;

public class Sentence {

    private ArrayList<PredicateLogic> sentence = new ArrayList<PredicateLogic>();
    private IParsingStrategy parser;

    /**
     * @return the parser
     */
    public IParsingStrategy getParser() {
        return parser;
    }

    /**
     * @param parser the parser to set
     */
    public void setParser(IParsingStrategy parser) {
        this.parser = parser;
    }

    public Sentence(IParsingStrategy parserType) {
        parser = parserType;
    }

    /**
     * Construct an empty sentence
     */
    protected Sentence() {
    }

    /**
     * add an element to the sentence
     * @param element
     */
    public void add(PredicateLogic element) {
        sentence.add(element);

    }

    /**
     * add a sentence to a specific position.
     * @param index
     * @param element
     */
    public void add(int index, PredicateLogic element) {
        sentence.add(index, element);
    }

    /**
     * Adds all the elements of the specified sentence to this sentence, according to the iterator sequence
     * @param sentence
     */
    public void addAll(Sentence sentence) {
        this.sentence.addAll(sentence.getSentence());
    }

    /**
     * remove an element from it's position. Shift the remaining elements to the left
     * @param indexOf
     */
    public void remove(int indexOf) {
        sentence.remove(indexOf);
    }

    @Override
    public String toString() {
        String returnString = "";
        Iterator<PredicateLogic> iterator = sentence.iterator();
        while (iterator.hasNext()) {
            PredicateLogic term = iterator.next();
            if (term.getClass().equals(LogicPredicate.class)) {
                returnString += term.getName();
                if (iterator.hasNext()){
                    returnString+="(" + iterator.next().getName() + ")";
                }
            } else {
                returnString += term.getName();
            }
        }
        return returnString;

    }

    /**
     * Get actual implementation of the sentence
     * @return
     */
    public ArrayList<PredicateLogic> getSentence() {
        return sentence;
    }

    /**
     * Size of the sentence
     * @return returns the size of the sentence (in elements)
     */
    public int size() {
        return sentence.size();
    }

    /**
     * Get the index of some element. or -1 if there's no such element
     * @param element
     * @return
     */
    public int indexOf(PredicateLogic element) {
        return sentence.indexOf(element);
    }

    /**
     * Get the element of the index position
     * @param index
     * @return
     */
    public PredicateLogic get(int index) {
        return sentence.get(index);
    }

    /**
     * Returns a String showing the sentence "as is"
     * @return
     */
    public String rawFormat() {
        System.out.println("raw format sentence");
        String str = "";
        for (PredicateLogic i : sentence) {
            str += i.getName();
        }
        return str;
    }

    /**
     * Set a sentence
     * @param sentence
     */
    protected void setSentence(ArrayList<PredicateLogic> sentence) {
        this.sentence = sentence;
    }

    /**
     * Parse the sentence
     * @return
     * @throws UnBalancedExpressionException
     * @throws UnDecidibleValueException
     * @throws IllegalAccessError
     */
    public boolean parse() throws UnBalancedExpressionException, UnDecidibleValueException, IllegalAccessError {
        if (parser == null) {
            throw new IllegalAccessError("no parser defined for this sentence");
        }

        return parser.parseSentence(this);
    }

    @Override
    public Sentence clone() {
        Sentence clonedSentence = new Sentence(this.getParser());
        for (PredicateLogic element : sentence) {
            if (element.getClass().equals(PredicateVariable.class)) {
                PredicateVariable<?> clonedItem = ((PredicateVariable<?>) element).clone();
                clonedSentence.add(clonedItem);
            } else {
                if (element.getClass().equals(PredicateConstant.class)) {
                    PredicateConstant<?> clonedItem = ((PredicateConstant<?>) element).clone();
                    clonedSentence.add(clonedItem);
                } else {
                    clonedSentence.add(element);
                }
            }
        }
        return clonedSentence;
    }

    /**
     * Returns a String containing the sentence showing the elements in it and the values inside the constants and variables
     * @return
     */
    public String toStringWithValues() {
        String returnString = "";
        Iterator<PredicateLogic> iterator = sentence.iterator();
        while (iterator.hasNext()) {
            PredicateLogic term = iterator.next();
            if (term.getClass().equals(LogicPredicate.class)) {
                if (iterator.hasNext()) {
                    PredicateLogic nextItem = iterator.next();
                    if (nextItem.getClass().equals(PredicateConstant.class)) {

                        returnString += term.getName() + "(" + ((PredicateConstant<?>) nextItem).getValue() + ")";

                    } else {
                        if (nextItem.getClass().equals(PredicateVariable.class)) {
                            returnString += term.getName() + "(" + ((PredicateVariable<?>) nextItem).getValue() + ")";
                        } else {
                            returnString += term.getName();
                        }
                    }
                } else {
                    returnString += term.getName();
                }
            } else {
                returnString += term.getName();
            }
        }
        return returnString;

    }

    /**
     * Removes all elements from this sentence.
     */
    public void clear() {
        sentence.clear();
    }
}
